package ma.mapharmasys.webapp.action;

import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import ma.mapharmasys.Constants;
import ma.mapharmasys.model.User;
import ma.mapharmasys.service.MailEngine;
import ma.mapharmasys.service.UserManager;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.NullComparator;
import org.apache.commons.collections.comparators.ReverseComparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.mail.SimpleMailMessage;

public class BasePage {
	protected final Log log = LogFactory.getLog(getClass());
	protected UserManager userManager;
	protected MailEngine mailEngine;
	protected SimpleMailMessage message;
	protected String templateName;
	protected FacesContext facesContext;
	protected String sortColumn;
	protected boolean ascending = true;
	protected boolean nullsAreHigh;
	protected String currentMenu;

	public FacesContext getFacesContext() {
		return FacesContext.getCurrentInstance();
	}

	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}

	
	// Convenience methods ====================================================
	public String getParameter(String name) {
		return getRequest().getParameter(name);
	}

	public String getCurrentMenu() {
		currentMenu = FacesContext.getCurrentInstance().getViewRoot()
				.getViewId();
		if (currentMenu != null && currentMenu.contains("userForm")
				&& "list".equals(getParameter("from"))) {
			currentMenu = "admin/userForme.xhtml";
		}
		return currentMenu;
	}

	public Map getCountries() {
		CountryModel model = new CountryModel();
		return model.getCountries(getRequest().getLocale());
	}

	public String getBundleName() {
		return getFacesContext().getApplication().getMessageBundle();
	}

	public ResourceBundle getBundle() {
		ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();
		return ResourceBundle.getBundle(getBundleName(), getRequest()
				.getLocale(), classLoader);
	}

	public String getText(String key) {
		String message;

		try {
			message = getBundle().getString(key);
		} catch (java.util.MissingResourceException mre) {
			log.warn("Missing key for '" + key + "'");
			return "???" + key + "???";
		}

		return message;
	}

	public String getText(String key, Object arg) {
		if (arg == null) {
			return getText(key);
		}

		MessageFormat form = new MessageFormat(getBundle().getString(key));

		if (arg instanceof String) {
			return form.format(new Object[] { arg });
		} else if (arg instanceof Object[]) {
			return form.format(arg);
		} else {
			log.error("arg '" + arg + "' not String or Object[]");

			return "";
		}
	}

	@SuppressWarnings("unchecked")
	protected void addMessage(String key, Object arg) {
		List<String> messages = (List) getSession().getAttribute("messages");

		if (messages == null) {
			messages = new ArrayList<String>();
		}

		messages.add(getText(key, arg));
		getSession().setAttribute("messages", messages);
	}

	protected void addMessage(String key) {
		addMessage(key, null);
	}

	@SuppressWarnings("unchecked")
	protected void addError(String key, Object arg) {
		List<String> errors = (List) getSession().getAttribute("errors");

		if (errors == null) {
			errors = new ArrayList<String>();
		}

		// if key contains a space, don't look it up, it's likely a raw message
		if (key.contains(" ") && arg == null) {
			errors.add(key);
		} else {
			errors.add(getText(key, arg));
		}

		getSession().setAttribute("errors", errors);
	}

	protected void addError(String key) {
		addError(key, null);
	}

	/**
	 * Convenience method for unit tests.
	 * 
	 * @return boolean indicator of an "errors" attribute in the session
	 */
	public boolean hasErrors() {
		return (getSession().getAttribute("errors") != null);
	}

	/**
	 * Servlet API Convenience method
	 * 
	 * @return HttpServletRequest from the FacesContext
	 */
	protected HttpServletRequest getRequest() {
		return (HttpServletRequest) getFacesContext().getExternalContext()
				.getRequest();
	}

	/**
	 * Servlet API Convenience method
	 * 
	 * @return the current user's session
	 */
	protected HttpSession getSession() {
		return getRequest().getSession();
	}

	/**
	 * Servlet API Convenience method
	 * 
	 * @return HttpServletResponse from the FacesContext
	 */
	protected HttpServletResponse getResponse() {
		return (HttpServletResponse) getFacesContext().getExternalContext()
				.getResponse();
	}

	/**
	 * Servlet API Convenience method
	 * 
	 * @return the ServletContext form the FacesContext
	 */
	protected ServletContext getServletContext() {
		return (ServletContext) getFacesContext().getExternalContext()
				.getContext();
	}

	/**
	 * Convenience method to get the Configuration HashMap from the servlet
	 * context.
	 * 
	 * @return the user's populated form from the session
	 */
	protected Map getConfiguration() {
		Map config = (HashMap) getServletContext().getAttribute(
				Constants.CONFIG);

		// so unit tests don't puke when nothing's been set
		if (config == null) {
			return new HashMap();
		}

		return config;
	}

	/**
	 * Convenience message to send messages to users, includes app URL as
	 * footer.
	 * 
	 * @param user
	 *            the user to send the message to
	 * @param msg
	 *            the message to send
	 * @param url
	 *            the application's URL
	 */
	protected void sendUserMessage(User user, String msg, String url) {
		if (log.isDebugEnabled()) {
			log.debug("sending e-mail to user [" + user.getEmail() + "]...");
		}

		message.setTo(user.getFullName() + "<" + user.getEmail() + ">");

		Map<String, Serializable> model = new HashMap<String, Serializable>();
		model.put("user", user);

		// TODO: once you figure out how to get the global resource bundle in
		// WebWork, then figure it out here too. In the meantime, the Username
		// and Password labels are hard-coded into the template.
		// model.put("bundle", getTexts());
		model.put("message", msg);
		model.put("applicationURL", url);
		mailEngine.sendMessage(message, templateName, model);
	}

	public void setMailEngine(MailEngine mailEngine) {
		this.mailEngine = mailEngine;
	}

	public void setMessage(SimpleMailMessage message) {
		this.message = message;
	}

	public void setTemplateName(String templateName) {
		this.templateName = templateName;
	}

	// The following methods are used by p:dataTable for sorting.
	public String getSortColumn() {
		return sortColumn;
	}

	public void setSortColumn(String sortColumn) {
		this.sortColumn = sortColumn;
	}

	public boolean isAscending() {
		return ascending;
	}

	public void setAscending(boolean ascending) {
		this.ascending = ascending;
	}

	/**
	 * Sort list according to which column has been clicked on.
	 * 
	 * @param list
	 *            the java.util.List to sort
	 * @return ordered list
	 */
	@SuppressWarnings("unchecked")
	protected List sort(List list) {
		Comparator comparator = new BeanComparator(sortColumn,
				new NullComparator(nullsAreHigh));
		if (!ascending) {
			comparator = new ReverseComparator(comparator);
		}
		Collections.sort(list, comparator);
		return list;
	}

	@SuppressWarnings("unchecked")
	protected List sort(List list, String sortColumn) {
		Comparator comparator = new BeanComparator(sortColumn,
				new NullComparator(nullsAreHigh));
		if (!ascending) {
			comparator = new ReverseComparator(comparator);
		}
		Collections.sort(list, comparator);
		return list;
	}

}
